package main

import (
	"fmt"
	"reflect"
)

func main() {
	var a Monster = Monster{
		Name:  "黄鼠狼精",
		Age:   400,
		Score: 30.8,
		Sex:   0,
	}

	getFiledInfo(a)
	reSetFiledValue(a)
	callMethod(a)
	createStruct(a)

}

// createStruct
//
//	@Description: 创建结构体实例
//	@param a
func createStruct(a interface{}) {
	//获取Monster结构体的类型
	monsterType := reflect.TypeOf(a)
	kind := monsterType.Kind()
	if kind != reflect.Struct {
		fmt.Println("不是结构体")
		return
	}
	//创建Monster结构体实例
	monsterValue := reflect.New(monsterType).Elem()
	//获取字段数量
	numField := monsterType.NumField()
	for i := 0; i < numField; i++ {
		//获取字段值,现在均为默认值
		v := monsterValue.Field(i)
		//获取字段的类别,然后进行赋值
		k := v.Kind()
		switch k {
		case reflect.Int:
			v.SetInt(99)
		case reflect.Int8:
			v.SetInt(1)
		case reflect.Float64:
			v.SetFloat(1999.9)
		case reflect.String:
			v.SetString("黄狮子")
		}
	}
	//value -> interface{} ->类型断言
	monster := monsterValue.Interface().(Monster)
	fmt.Println(monster)
}

// getFiledInfo
//
//	@Description: 获取字段信息
//	@param a 结构体/结构体指针
func getFiledInfo(a interface{}) {
	valueOf := reflect.ValueOf(a)
	typeOf := reflect.TypeOf(a)
	kind := typeOf.Kind()
	//传递参数是结构体
	if kind == reflect.Struct {
		fmt.Println("+++++++++传入参数是结构体+++++++++")
		num := typeOf.NumField()
		fmt.Printf("结构体有 %d 个字段: \n", num)
		for i := 0; i < num; i++ {
			structField := typeOf.Field(i)
			v := valueOf.Field(i)
			fmt.Printf("字段类型=%v 字段名=%v  tag=%v 值=%v  \n", structField.Type, structField.Name, structField.Tag.Get("json"), v.Interface())
		}
	} else if kind == reflect.Ptr {
		fmt.Println("+++++++++传入参数是指针+++++++++")
		//获取指针指向的值
		elem := valueOf.Elem()
		numField := elem.NumField()
		fmt.Printf("结构体有 %d 个字段: \n", numField)
		for i := 0; i < numField; i++ {
			//获取字段值
			v := elem.Field(i)
			//获取elem的类型，再获取字段的类型
			structField := elem.Type().Field(i)
			fmt.Printf("字段类型=%v 字段名=%v  tag=%v 值=%v  \n", structField.Type, structField.Name, structField.Tag.Get("json"), v.Interface())
		}
	} else {
		fmt.Println("不是结构体  也不是指针~")
	}

}

func callMethod(a interface{}) {
	of := reflect.TypeOf(a)
	val := reflect.ValueOf(a)
	kind := val.Kind()
	if kind != reflect.Struct {
		return
	}
	numOfMethod := val.NumMethod()
	fmt.Printf("结构体有 %d 个方法: \n", numOfMethod)

	for i := 0; i < numOfMethod; i++ {
		method := of.Method(i)
		fmt.Printf("方法名=%v 方法=%v \n", method.Name, method.Type)
	}
	fmt.Println()

	//反射调用方法~
	//方法的排序默认是按照 函数名的ASCII码进行排序的
	fmt.Println("执行", of.Method(0).Name, "方法：")
	var params01 []reflect.Value = make([]reflect.Value, 0)
	params01 = append(params01, reflect.ValueOf(10))
	params01 = append(params01, reflect.ValueOf(40))
	res := val.Method(0).Call(params01)
	fmt.Printf("res= %v", res[0].Int())

}

// reSetFiledValue
//
//	@Description: 设置结构体的字段值
//	@param a 传递的必须是指针
func reSetFiledValue(a interface{}) {
	monsterValue := reflect.ValueOf(&a)
	monsterType := reflect.TypeOf(a)
	kind := monsterType.Kind()
	if kind == reflect.Ptr {
		fmt.Println("+++++++++传入参数是指针+++++++++")
		elem := monsterValue.Elem()
		num := elem.NumField()
		fmt.Println("原来的字段值：", elem.Interface())
		fmt.Printf("结构体有 %d 个字段: \n", num)
		for i := 0; i < num; i++ {
			value := elem.Field(i)
			k := value.Kind()
			switch k {
			case reflect.Int:
				value.SetInt(99)
			case reflect.Int8:
				value.SetInt(1)
			case reflect.Float64:
				value.SetFloat(1999.9)
			case reflect.String:
				value.SetString("黄狮子")
			}
		}
		fmt.Println("修改后的结构体字段值: ", elem.Interface())
	}

	if kind == reflect.Struct {
		fmt.Println("+++++++++传入参数是结构体+++++++++")

	}

}

type Monster struct {
	Name  string  `json:"monsterName"`
	Age   int     `json:"monsterAge"`
	Score float64 `json:"成绩"`
	Sex   int8
}

// GetSum
//
//	@Description:
//	@receiver m
//	@param n1
//	@param n2
//	@return int
func (m Monster) GetSum(n1 int, n2 int) int {
	return n1 + n2
}

// Set
//
//	@Description: 给属性赋值
//	@receiver m
//	@param name
//	@param age
//	@param score
//	@param sex
func (m Monster) Set(name string, age int, score float64, sex int8) {
	m.Name = name
	m.Age = age
	m.Score = score
	m.Sex = sex
}
func (m Monster) Print() {
	fmt.Println("-----start-----")
	fmt.Println(m)
	fmt.Println("-----end-----")
}
